using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Genetic_Tetris
{
    public partial class Form1 : Form
    {
        Board myBoard;
        PieceFactory pieceFac;
        Piece nextPiece;
        Piece currentPiece;
        MoveDecider decider;
        HeuristicConstants heuristic;
        Timer timer;
        int pieceCount;
        int rowCount;
        int doubleCount;
        int tripleCount;
        int tetrisCount;

        MoveDecider md = new MoveDecider();
        Move myMove;


        Random rand = new Random();

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //Init();
            this.KeyUp += new KeyEventHandler(Form1_KeyUp);

        }

        void Form1_KeyUp(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Left:
                    MovePiece(currentPiece, -1);
                    //update screen
                    textBox1.Text = myBoard.ToString();
                    //labelHeuristic.Text = EvalCurrentMove();
                    textBoxHeuristic.Text = EvalCurrentMove();
                    break;

                case Keys.Right:
                    MovePiece(currentPiece, 1);
                    //update screen
                    textBox1.Text = myBoard.ToString();
                    //labelHeuristic.Text = EvalCurrentMove();
                    textBoxHeuristic.Text = EvalCurrentMove();
                    break;

                case Keys.Up:
                    currentPiece.RotateLeft();
                    //update screen
                    textBox1.Text = myBoard.ToString();
                    //labelHeuristic.Text = EvalCurrentMove();
                    textBoxHeuristic.Text = EvalCurrentMove();
                    break;

                case Keys.Down:
                    //place the piece in the row its in
                    Piece tempPiece = pieceFac.MakePiece((PieceFactory.PieceType)currentPiece.Type);
                    while (tempPiece.Rotation != currentPiece.Rotation)
                    {
                        tempPiece.RotateLeft();
                    }
                    myBoard.PlacePieceInColumn(tempPiece, myBoard.CurrentPieceColumn);
                    myBoard.ProcessCompleteRows();
                    pieceCount++;


                    currentPiece = pieceFac.MakePiece((PieceFactory.PieceType)nextPiece.Type);
                    PutPieceInColumn(currentPiece, 5);
                    myBoard.CurrentPiece = currentPiece;
                    myBoard.CurrentPieceColumn = 5;

                    nextPiece = pieceFac.MakePiece();
                    ShowNextPiece();




                    //label1.Text = myBoard.ToString();
                    textBox1.Text = myBoard.ToString();
                    labelCount.Text = pieceCount.ToString();
                    labelRowCount.Text = rowCount.ToString();
                    break;


                default:
                    break;



            }

        }

        private void MovePiece(Piece pieceIn, int deltaX)
        {
            int leftMost = int.MaxValue;
            int rightMost = int.MinValue;

            //move the piece
            myBoard.CurrentPieceColumn += deltaX;
            for (int i = 0; i < pieceIn.Blocks.Length; i++)
            {
                pieceIn.Blocks[i].X = pieceIn.Blocks[i].X + deltaX;

                if (pieceIn.Blocks[i].X < leftMost)
                {
                    leftMost = pieceIn.Blocks[i].X;
                }

                if (pieceIn.Blocks[i].X > rightMost)
                {
                    rightMost = pieceIn.Blocks[i].X;
                }
            }

            //if we went off the edge of the board,
            //move it back

            if (leftMost < 0 || rightMost >= myBoard.WIDTH)
            {
                myBoard.CurrentPieceColumn -= deltaX;
                for (int i = 0; i < pieceIn.Blocks.Length; i++)
                {
                    pieceIn.Blocks[i].X = pieceIn.Blocks[i].X - deltaX;
                }
            }
        }
        private void PutPieceInColumn(Piece pieceIn, int colNum)
        {
            for (int i = 0; i < pieceIn.Blocks.Length; i++)
            {
                pieceIn.Blocks[i].X = pieceIn.Blocks[i].X + colNum;
            }

        }

        public void Init()
        {
            timer = new Timer();
            timer.Interval = trackBar1.Value;
            timer.Tick += new EventHandler(timer_Tick);


            myBoard = new Board();
            myBoard.RowRemoved += new EventHandler(myBoard_RowRemoved);
            myBoard.DoubleRowRemoved += new EventHandler(myBoard_DoubleRowRemoved);
            myBoard.TripleRowRemoved += new EventHandler(myBoard_TripleRowRemoved);
            myBoard.QuadRowRemoved += new EventHandler(myBoard_QuadRowRemoved);

            pieceFac = new PieceFactory();
            if (radioButtonFixed.Checked)
            {
                pieceFac.RandomSeed = Int32.Parse(textBoxSeed.Text);
            }
            else if (radioButtonRandom.Checked)
            {
                pieceFac.RandomSeed = rand.Next();
            }
            else
            {
                throw new Exception("Unknown checkbox state!");
            }


            nextPiece = pieceFac.MakePiece();
            currentPiece = pieceFac.MakePiece((PieceFactory.PieceType)nextPiece.Type);
            PutPieceInColumn(currentPiece, 5);
            myBoard.CurrentPiece = currentPiece;
            myBoard.CurrentPieceColumn = 5;

            ShowNextPiece();
            decider = new MoveDecider();
            heuristic = new HeuristicConstants();

            pieceCount = 0;
            rowCount = 0;
            doubleCount = 0;
            tripleCount = 0;
            tetrisCount = 0;

            //label1.Text = myBoard.ToString();
            textBox1.Text = myBoard.ToString();
            labelCount.Text = pieceCount.ToString();
            labelRowCount.Text = rowCount.ToString();
            labelDouble.Text = doubleCount.ToString();
            labelTriple.Text = tripleCount.ToString();
            labelTetris.Text = tetrisCount.ToString();

        }





        private void ShowNextPiece()
        {
            string[,] pieceGrid = new string[5, 5];


            for (int i = 0; i < nextPiece.Blocks.Length; i++)
            {
                int xLoc = nextPiece.Blocks[i].X + 2;
                int yLoc = nextPiece.Blocks[i].Y + 2;
                pieceGrid[xLoc, yLoc] = Board.BLOCK;

            }

            string temp = "";
            for (int y = 0; y < 5; y++)
            {
                for (int x = 0; x < 5; x++)
                {
                    if (pieceGrid[x, y] != null)
                    {
                        temp += pieceGrid[x, y];
                    }
                    else
                    {
                        temp += " ";
                    }
                }
                temp += "\n";
            }

            label1.Text = temp;
        }

        void myBoard_RowRemoved(object sender, EventArgs e)
        {
            rowCount++;
            labelRowCount.Text = rowCount.ToString();
        }
        void myBoard_DoubleRowRemoved(object sender, EventArgs e)
        {
            doubleCount++;
            labelDouble.Text = doubleCount.ToString();
        }
        void myBoard_TripleRowRemoved(object sender, EventArgs e)
        {
            tripleCount++;
            labelTriple.Text = tripleCount.ToString();

        }
        void myBoard_QuadRowRemoved(object sender, EventArgs e)
        {
            tetrisCount++;
            labelTetris.Text = tetrisCount.ToString();
        }

        void timer_Tick(object sender, EventArgs e)
        {
            myMove = decider.DecideMove(myBoard, pieceFac.MakePiece((PieceFactory.PieceType)currentPiece.Type), heuristic);
            if (myMove != null)
            {
                myBoard.PlacePieceInColumn(myMove.Piece, myMove.Column);
                myBoard.ProcessCompleteRows();
                pieceCount++;
            }
            else
            {
                timer.Enabled = false;
                //MessageBox.Show("Game Over!!!!!!");
            }


            currentPiece = pieceFac.MakePiece((PieceFactory.PieceType)nextPiece.Type);
            PutPieceInColumn(currentPiece, 5);
            myBoard.CurrentPiece = currentPiece;
            myBoard.CurrentPieceColumn = 5;

            nextPiece = pieceFac.MakePiece();
            
            
            ShowNextPiece();
            textBox1.Text = myBoard.ToString();
            labelCount.Text = pieceCount.ToString();
            labelRowCount.Text = rowCount.ToString();
            

        }

        private string EvalCurrentMove()
        {
            string text = "";
            //take the position of the currentPiece,
            //and get all the heuristic values and total
            //heuristic fitness

            Board tempBoard = new Board();
            tempBoard.Grid = (bool[,])myBoard.Grid.Clone();


            Piece tempPiece = pieceFac.MakePiece((PieceFactory.PieceType)currentPiece.Type);
            while (tempPiece.Rotation != currentPiece.Rotation)
            {
                tempPiece.RotateLeft();
            }

            if (myBoard.IsValidMove(tempPiece, myBoard.CurrentPieceColumn))
            {
                tempBoard.PlacePieceInColumn(tempPiece, myBoard.CurrentPieceColumn);
            }



            //Rows completed
            int completeRows = tempBoard.GetCompleteRowCount();

            tempBoard.ProcessCompleteRows();

            int maxHeight = tempBoard.GetMaxHeight();



            //Gap Count
            int gapCount = tempBoard.GetGapCount();

            //holes per row
            double WeightedBlocksPerRow = tempBoard.GetWeightedBlocksPerRow();

            double averageHeight = tempBoard.GetAverageHeight();
            int alternations = tempBoard.GetAlternations();
            double burialDepth = tempBoard.GetBurialDepth();

            double fitness = 0;
            fitness += (maxHeight * heuristic.Constants["MaxBlockHeight"]);
            fitness += (completeRows * heuristic.Constants["RowsCompleted"]);
            fitness += (gapCount * heuristic.Constants["GapCount"]);
            fitness += (WeightedBlocksPerRow * heuristic.Constants["WeightedBlocksPerRow"]);
            fitness += (averageHeight * heuristic.Constants["AverageHeight"]);
            fitness += (alternations * heuristic.Constants["Alternations"]);
            fitness += (burialDepth * heuristic.Constants["BurialDepth"]);
            


            //add up raw scores modified by heuristic values
            double maxHeightFitness = (maxHeight * heuristic.Constants["MaxBlockHeight"]);
            double completeRowsFitness = (completeRows * heuristic.Constants["RowsCompleted"]);
            double gapcountFitness = (gapCount * heuristic.Constants["GapCount"]);
            double WeightedBlocksPerRowFitness = (WeightedBlocksPerRow * heuristic.Constants["WeightedBlocksPerRow"]);
            double averageHeightFitness = (averageHeight * heuristic.Constants["AverageHeight"]);
            double alternationsFitness = (alternations * heuristic.Constants["Alternations"]);
            double burialDepthFitness = (burialDepth * heuristic.Constants["BurialDepth"]);


            text += "maxHeight " + maxHeight + " " + maxHeightFitness + "\r\n";
            text += "completeRows " + completeRows + " " + completeRowsFitness + "\r\n";
            text += "gapCount " + gapCount + " " + gapcountFitness + "\r\n";
            text += "WeightedBlocksPerRow " + WeightedBlocksPerRow + " " + WeightedBlocksPerRowFitness + "\r\n";
            text += "averageHeight " + averageHeight + " " + averageHeightFitness + "\r\n";
            text += "alternations " + alternations + " " + alternationsFitness + "\r\n";
            text += "burial depth " + burialDepth + " " + burialDepthFitness + "\r\n";
            text += "total " + fitness.ToString();



            return text;
        }



        private void button1_Click(object sender, EventArgs e)
        {
            if (timer.Enabled)
            {
                timer.Enabled = false;
                button1.Text = "Go";
            }
            else
            {
                timer.Enabled = true;
                button1.Text = "Stop";
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            Init();
        }

        private void button3_Click(object sender, EventArgs e)
        {
            timer_Tick(null, null);
        }



        private void button4_Click_1(object sender, EventArgs e)
        {
            Random tempRand = new Random();
            textBoxSeed.Text = tempRand.Next(10000).ToString();
        }

        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            timer.Interval = trackBar1.Value;
        }


    }
}